#!/usr/bin/env python
# encoding: utf-8
"""
csvprocessor.py

Created by Paul Gower on 2010-05-04.
Copyright (c) 2010 __MyCompanyName__. All rights reserved.
"""

import sys
import os
import csv
import re

class CSVProcessor(object):
  """Processes a TimeChart CSV file into a python object"""
  
  def __init__(self, filename):
    self.data = {} # this is where the processed data will be stored
    csv_file = open(filename)
    chunks = self.seperate_tables(csv_file)
    for i,chunk in enumerate(chunks):
      chunks[i] = self.clean_chunk(chunk)
    for chunk in chunks:
      self.convert_chunk(chunk)

  def seperate_tables(self, tcdata):
    """
    take the text from the timechart file and split it into individual time tables, return the result as a list of raw table data chunks
    Args:
      tcdata: the raw text as read from the timechart output file
    """
    # split the whole thing into chunks
    chunks = []
    splitter = re.compile('(Student|Teacher) Timetable')
    current_chunk = ""
    for line in tcdata:
      if splitter.match(line):
        chunks.append(current_chunk)
        current_chunk = ""
      else:
        current_chunk = current_chunk + line
    
    # clean up the chunks, anything that doesnt have "DAY 1" in it is discarded
    cleaner = re.compile('DAY 1')
    for chunk in chunks:
      if not cleaner.search(chunk):
        chunks.remove(chunk)
    
    # return the chunks
    return chunks
    
  def convert_chunk(self, chunk):
    """
    Take a chunk of raw timechart text data and turn it into entries in self.data
    Args:
      chunk: a chunk of raw timechart text data
    """
    reader = csv.reader([chunk], delimiter=",")
    for row in reader:
      row = row
    # get the data out and put it in self.data
    # teachers start with a 2 letter code, students start with a full name
    if len(row[0]) == 2:
      # should be a teacher
      self.tt_type = 'teacher'
      name = self.multi_split(row[1]," ","/")
      code = name[0][0:3] + name[1][0:1] + "0"
      name = name[1] + " " + name[0]
    else:
      # should be a student
      self.tt_type = 'student'
      code = row[0].split(" ",1)
      name = code[1] + " " + code[0]
      code = code[0][0:3] + code[1][0:1] + "0" # this will be wrong for some cases where the username prefix is 1
    self.data[code] = []
    if not self.data.has_key('codes'):
      self.data['codes'] = {code:name}
    else:
      self.data['codes'][code] = name
    i = row.index('p.1') + 1
    chunk_entries = [i] + [i + x*31 for x in range(1,6)]
    print chunk_entries
    for p in chunk_entries:
      print "Period:" + str(p) + " " + str(p+30)
      pd = self.convert_period(row[p:p+30])
      self.data[code].append(pd)

  def clean_chunk(self, chunk):
    """
    Take a chunk of raw timechart text data and clean the misc text from around it
    Args:
      chunk: a chunk of raw timechart data
    """
    rm_newlines = re.compile("[\n\r]*")
    chunk = rm_newlines.sub("",chunk)
    rm_leading_comma = re.compile("^,")
    chunk = rm_leading_comma.sub("",chunk)
    rm_trailing_info = re.compile(",Total time.*")
    chunk = rm_trailing_info.sub("",chunk)
    rm_student_trailing_info = re.compile("ST\. MONICA'S COLLEGE.*")
    chunk = rm_student_trailing_info.sub("",chunk)
    return chunk
    
  def convert_period(self, period):
    """
    Convert 30 cells into periods for a 10 day timetable a period is 3 cells long and the data is stored what, where, who.
    If a period is empty then store None.
    Args:
      period: a list of 30 cells
    """
    print period
    i = [3*x for x in range(10)]
    r = []
    for j in i:
      if len(period[j]) > 0:
        if self.tt_type == 'teacher':
          r.append({'what':period[j], 'where':period[j+1], 'who':period[j+2]})
        else:
          r.append({'what':period[j], 'who':period[j+1], 'where':period[j+2]})
      else:
        r.append(None)
    return r
    
  def get_data_for_person(self, person):
    """
    Get data for the given person code (or name?) and return it. This function will also rearrange the data before sending it so that the return value
    is a list containing 10 sublists which each contain all the periods for that day. Empty periods will be filled with the None value.
    Args:
      person: the two letter person code required
    """
    if not self.data.has_key(person):
      raise Exception("Invalid person Key")
    data = self.data[person]
    reorg_data = []
    # for each day
    for i in range(10):
      day_data = []
      for j in data:
        day_data.append(j[i])
      reorg_data.append(day_data)
    return reorg_data
  
  def get_persons(self):
    """
    Return a list of the persons that we have seen in the timechart file
    """
    return self.data['codes'].keys()
    
  def multi_split(self, string, *splitters):
    """
    Split the given string with the given splitters. The first splitter that returns more than one split is returned
    Args:
      string: the string to split
      splitters: the splitters to use when splitting
    """
    for splitter in splitters:
      r = string.split(splitter)
      if len(r) > 1:
        return r
    return [string]
    

def main():
  # for testing purposes, use ics_creator.py to generate the .ics files
	c = CSVProcessor("student_ttable_export.TXT")
	print "======================================================================="
	d = CSVProcessor("teacher_ttable_export.TXT")


if __name__ == '__main__':
	main()

